home *** CD-ROM | disk | FTP | other *** search
- /*
-
- Copyright (C) 1996 John W. Eaton
-
- This file is part of Octave.
-
- Octave is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- Octave is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with Octave; see the file COPYING. If not, write to the Free
- Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- */
-
- /* Modified by Klaus Gebhardt, 1996 */
-
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
-
- #include <csignal>
- #include <cstdlib>
- #include <cstring>
-
- #include <string>
-
- #include <iostream.h>
- #include <fstream.h>
- #include <strstream.h>
-
- #ifdef HAVE_UNISTD_H
- #ifdef HAVE_SYS_TYPES_H
- #include <sys/types.h>
- #endif
- #include <unistd.h>
- #endif
-
- #include "str-vec.h"
-
- #include <defaults.h>
- #include "defun.h"
- #include "dirfns.h"
- #include "error.h"
- #include "fn-cache.h"
- #include "gripes.h"
- #include "help.h"
- #include "input.h"
- #include "oct-obj.h"
- #include "pager.h"
- #include "pathsearch.h"
- #include "pt-const.h"
- #include "pt-exp.h"
- #include "pt-pr-code.h"
- #include "sighandlers.h"
- #include "symtab.h"
- #include "syswait.h"
- #include "toplev.h"
- #include "unwind-prot.h"
- #include "utils.h"
- #include "variables.h"
-
- #if defined (__EMX__)
- extern "C"
- {
- #include "info/info.h"
- #include "info/dribble.h"
- #include "info/terminal.h"
-
- extern int external_info_search ();
- extern int index_entry_exists ();
- extern int do_info_index_search ();
- extern void finish_info_session ();
- extern char *replace_in_documentation ();
- }
- #endif
-
- // Name of the info file specified on command line.
- // (--info-file file)
- string Vinfo_file;
-
- // Name of the info reader we'd like to use.
- // (--info-program program)
- string Vinfo_prog;
-
- // If TRUE, don't print additional help message in help and usage
- // functions.
- static bool Vsuppress_verbose_help_message;
-
- static help_list operators[] =
- {
- { "!",
- "Logical not operator. See also `~'.\n", },
-
- { "!=",
- "Logical not equals operator. See also `~' and `<>'.\n", },
-
- { "\"",
- "String delimiter.\n", },
-
- { "#",
- "Begin comment character. See also `%'.", },
-
- { "%",
- "Begin comment charcter. See also `#'.", },
-
- { "&",
- "Logical and operator. See also `&&'.", },
-
- { "&&",
- "Logical and operator. See also `&'.", },
-
- { "'",
- "Matrix transpose operator. For complex matrices, computes the\n\
- complex conjugate (Hermitian) transpose. See also `.''\n\
- \n\
- The single quote character may also be used to delimit strings, but\n\
- it is better to use the double quote character, since that is never\n\
- ambiguous", },
-
- { "(",
- "Array index or function argument delimiter.", },
-
- { ")",
- "Array index or function argument delimiter.", },
-
- { "*",
- "Multiplication operator. See also `.*'", },
-
- { "**",
- "Power operator. See also `^', `.**', and `.^'", },
-
- { "+",
- "Addition operator.", },
-
- { "++",
- "Increment operator. As in C, may be applied as a prefix or postfix operator.", },
-
- { ",",
- "Array index, function argument, or command separator.", },
-
- { "-",
- "Subtraction or unary negation operator.", },
-
- { "--",
- "Decrement operator. As in C, may be applied as a prefix or postfix operator.", },
-
- { ".'",
- "Matrix transpose operator. For complex matrices, computes the\n\
- transpose, *not* the complex conjugate transpose. See also `''.", },
-
- { ".*",
- "Element by element multiplication operator. See also `*'.", },
-
- { ".**",
- "Element by element power operator. See also `**', `^', and `.^'.", },
-
- { "./",
- "Element by element division operator. See also `/' and `\\'.", },
-
- { ".^",
- "Element by element power operator. See also `**', `^', and `.^'.", },
-
- { "/",
- "Right division. See also `\\' and `./'.", },
-
- { ":",
- "Select entire rows or columns of matrices.", },
-
- { ";",
- "Array row or command separator. See also `,'.", },
-
- { "<",
- "Less than operator.", },
-
- { "<=",
- "Less than or equals operator.", },
-
- { "<>",
- "Logical not equals operator. See also `!=' and `~='.", },
-
- { "=",
- "Assignment operator.", },
-
- { "==",
- "Equality test operator.", },
-
- { ">",
- "Greater than operator.", },
-
- { ">=",
- "Greater than or equals operator.", },
-
- { "[",
- "Return list delimiter. See also `]'.", },
-
- { "\\",
- "Left division operator. See also `/' and `./'.", },
-
- { "]",
- "Return list delimiter. See also `['.", },
-
- { "^",
- "Power operator. See also `**', `.^', and `.**.'", },
-
- { "|",
- "Logical or operator. See also `||'.", },
-
- { "||",
- "Logical or operator. See also `|'.", },
-
- { "~",
- "Logical not operator. See also `!' and `~'.", },
-
- { "~=",
- "Logical not equals operator. See also `<>' and `!='.", },
-
- { 0, 0, },
- };
-
- static help_list keywords[] =
- {
- { "all_va_args",
- "Pass all unnamed arguments to another function call.", },
-
- { "break",
- "Exit the innermost enclosing while or for loop.", },
-
- { "catch",
- "begin the cleanup part of a try-catch block", },
-
- { "continue",
- "Jump to the end of the innermost enclosing while or for loop.", },
-
- { "else",
- "Alternate action for an if block.", },
-
- { "elseif",
- "Alternate conditional test for an if block.", },
-
- { "end",
- "Mark the end of any for, if, while, or function block.", },
-
- { "end_try_catch",
- "Mark the end of an try-catch block.", },
-
- { "end_unwind_protect",
- "Mark the end of an unwind_protect block.", },
-
- { "endfor",
- "Mark the end of a for loop.", },
-
- { "endfunction",
- "Mark the end of a function.", },
-
- { "endif",
- "Mark the end of an if block.", },
-
- { "endwhile",
- "Mark the end of a while loop.", },
-
- { "for",
- "Begin a for loop.", },
-
- { "function",
- "Begin a function body.", },
-
- { "global",
- "Declare variables to have global scope.", },
-
- { "gplot",
- "Produce 2-D plots using gnuplot-like command syntax.", },
-
- { "gsplot",
- "Produce 3-D plots using gnuplot-like command syntax.", },
-
- { "if",
- "Begin an if block.", },
-
- { "return",
- "Return from a function.", },
-
- { "try",
- "Begin a try-catch block.", },
-
- { "unwind_protect",
- "Begin an unwind_protect block.", },
-
- { "unwind_protect_cleanup",
- "Begin the cleanup section of an unwind_protect block.", },
-
- { "while",
- "Begin a while loop.", },
-
- { 0, 0, },
- };
-
- // Return a copy of the operator or keyword names.
-
- string_vector
- names (help_list *lst, int& count)
- {
- string_vector retval;
-
- count = 0;
- help_list *ptr = lst;
- while (ptr->name)
- {
- count++;
- ptr++;
- }
-
- if (count > 0)
- {
- retval.resize (count);
-
- ptr = lst;
- for (int i = 0; i < count; i++)
- {
- retval[i] = ptr->name;
- ptr++;
- }
- }
-
- return retval;
- }
-
- help_list *
- operator_help (void)
- {
- return operators;
- }
-
- help_list *
- keyword_help (void)
- {
- return keywords;
- }
-
- #if defined (USE_GNU_INFO)
- static void
- additional_help_message (ostream& os)
- {
- if (! Vsuppress_verbose_help_message)
- os << "\n\
- Additional help for builtin functions, operators, and variables\n\
- is available in the on-line version of the manual.\n\
- \n\
- Use the command `help -i <topic>' to search the manual index.\n";
- }
- #else
- static void
- additional_help_message (ostream&)
- {
- }
- #endif
-
- void
- print_usage (const string& nm, int just_usage)
- {
- symbol_record *sym_rec = global_sym_tab->lookup (nm, 0, 0);
- if (sym_rec)
- {
- string h = sym_rec->help ();
-
- if (h.length () > 0)
- {
- octave_stdout << "\n*** " << nm << ":\n\n"
- << h << "\n";
-
- if (! just_usage)
- additional_help_message (octave_stdout);
- }
- }
- else
- warning ("no usage message found for `%s'", nm.c_str ());
- }
-
- static void
- display_names_from_help_list (ostream& os, help_list *list,
- const char *desc)
- {
- int count = 0;
- string_vector symbols = names (list, count);
- if (! symbols.empty ())
- {
- os << "\n*** " << desc << ":\n\n";
- symbols.list_in_columns (os);
- }
- }
-
- static string
- print_symbol_type (ostream& os, symbol_record *sym_rec,
- const string& name, int print)
- {
- string retval;
-
- if (sym_rec->is_user_function ())
- {
- tree_fvc *defn = sym_rec->def ();
-
- string fn = defn->fcn_file_name ();
-
- if (! fn.empty ())
- {
- string ff = fcn_file_in_path (fn);
-
- ff = ff.length () > 0 ? ff : fn;
-
- if (print)
- os << name
- << " is the function defined from:\n"
- << ff << "\n";
- else
- retval = ff;
- }
- else
- {
- if (print)
- os << name << " is a user-defined function\n";
- else
- retval = "user-defined function";
- }
- }
- else if (sym_rec->is_text_function ())
- {
- if (print)
- os << name << " is a builtin text-function\n";
- else
- retval = "builtin text-function";
- }
- else if (sym_rec->is_builtin_function ())
- {
- if (print)
- os << name << " is a builtin function\n";
- else
- retval = "builtin function";
- }
- else if (sym_rec->is_user_variable ())
- {
- if (print)
- os << name << " is a user-defined variable\n";
- else
- retval = "user-defined variable";
- }
- else if (sym_rec->is_builtin_variable ())
- {
- if (print)
- os << name << " is a builtin variable\n";
- else
- retval = "builtin variable";
- }
- else
- {
- if (print)
- os << "which: `" << name << "' has unknown type\n";
- else
- retval = "unknown type";
- }
-
- return retval;
- }
-
- static void
- display_symtab_names (ostream& os, const string_vector& names,
- int /* count */, const string& desc)
- {
- if (! names.empty ())
- {
- os << "\n*** " << desc << ":\n\n";
- names.list_in_columns (os);
- }
- }
-
- static void
- simple_help (void)
- {
- display_names_from_help_list (octave_stdout, operator_help (),
- "operators");
-
- display_names_from_help_list (octave_stdout, keyword_help (),
- "reserved words");
-
- #ifdef LIST_SYMBOLS
- #undef LIST_SYMBOLS
- #endif
- #define LIST_SYMBOLS(type, msg) \
- do \
- { \
- int count; \
- string_vector names = global_sym_tab->list (count, 0, 0, 1, type); \
- display_symtab_names (octave_stdout, names, count, msg); \
- } \
- while (0)
-
- // XXX FIXME XXX -- is this distinction needed?
-
- LIST_SYMBOLS (symbol_def::TEXT_FUNCTION,
- "text functions (these names are also reserved)");
-
- LIST_SYMBOLS (symbol_def::MAPPER_FUNCTION, "mapper functions");
-
- LIST_SYMBOLS (symbol_def::BUILTIN_FUNCTION, "general functions");
-
- LIST_SYMBOLS (symbol_def::BUILTIN_VARIABLE, "builtin variables");
-
- // Also need to list variables and currently compiled functions from
- // the symbol table, if there are any.
-
- // Also need to search octave_path for script files.
-
- dir_path p (Vload_path);
-
- string_vector dirs = p.all_directories ();
-
- int len = dirs.length ();
-
- for (int i = 0; i < len; i++)
- {
- string_vector names = octave_fcn_file_name_cache::list (dirs[i]);
-
- if (! names.empty ())
- {
- octave_stdout << "\n*** function files in "
- << make_absolute (dirs[i], Vcurrent_directory)
- << ":\n\n";
-
- names.list_in_columns (octave_stdout);
- }
- }
-
- additional_help_message (octave_stdout);
- }
-
- #if defined (USE_GNU_INFO)
- static int
- try_info (const string& nm)
- {
- if (Vinfo_prog.length () > 0)
- {
- int status = 0;
-
- static char *cmd_str = 0;
-
- delete [] cmd_str;
- cmd_str = 0;
-
- ostrstream cmd_buf;
-
- cmd_buf << Vinfo_prog << " --file " << Vinfo_file;
-
- string directory_name = Vinfo_file;
- size_t pos = directory_name.rfind ('/');
-
- if (pos != NPOS)
- {
- directory_name.resize (pos + 1);
- cmd_buf << " --directory " << directory_name;
- }
-
- if (nm.length () > 0)
- cmd_buf << " --index-search " << nm;
-
- cmd_buf << ends;
-
- cmd_str = cmd_buf.str ();
-
- volatile octave_interrupt_handler old_interrupt_handler
- = octave_ignore_interrupts ();
-
- status = system (cmd_str);
-
- octave_set_interrupt_handler (old_interrupt_handler);
-
- if (WIFEXITED (status))
- status = WEXITSTATUS (status);
- else
- status = 127;
-
- return status;
- }
- else
- {
- volatile octave_interrupt_handler old_interrupt_handler
- = octave_ignore_interrupts ();
-
- int status = 0;
-
- char *directory_name = strdup (Vinfo_file.c_str ());
- char *temp = filename_non_directory (directory_name);
-
- if (temp != directory_name)
- {
- *temp = 0;
- info_add_path (directory_name, INFOPATH_PREPEND);
- }
-
- delete [] directory_name;
-
- NODE *initial_node = info_get_node (Vinfo_file.c_str (), 0);
-
- if (! initial_node) status = 127;
- else
- {
- status = external_info_search(initial_node, 0,
- Vinfo_file.c_str (), nm.c_str ());
- if (status == 1)
- {
- char *format = replace_in_documentation
- ("Type \"\\[quit]\" to quit, \"\\[get-help-window]\" for help.");
- window_message_in_echo_area (format);
-
- info_read_and_dispatch ();
-
- #ifdef __EMX__
- terminal_goto_xy (0, screenheight - 2);
- #else
- terminal_goto_xy (0, screenheight - 1);
- #endif
- terminal_clear_to_eol ();
- terminal_unprep_terminal ();
- }
-
- status = status * status - 1;
-
- finish_info_session (initial_node, 0);
- }
-
- octave_set_interrupt_handler (old_interrupt_handler);
-
- return status;
- }
- }
-
- static void
- help_from_info (const string_vector& argv, int idx, int argc)
- {
- if (idx == argc)
- {
- int status = try_info (string ());
-
- if (status)
- {
- if (status < 0)
- {
- message ("help", "sorry, `%s' is not indexed in the manual",
- string ().c_str ());
- sleep (2);
- }
- else error ("help: unable to find info!");
- }
- }
- else
- {
- for (int i = idx; i < argc; i++)
- {
- int status = try_info (argv[i]);
-
- if (status)
- {
- if (status < 0)
- {
- message ("help",
- "sorry, `%s' is not indexed in the manual",
- argv[i].c_str ());
- sleep (2);
- }
- else
- {
- error ("help: unable to find info!");
- break;
- }
- }
- }
- }
- }
- #else
- static void
- help_from_info (const string_vector&, int, int)
- {
- message (0, "sorry, help -i is not available in this version of Octave");
- }
- #endif
-
- int
- help_from_list (ostream& os, const help_list *list,
- const string& nm, int usage)
- {
- char *name;
- while ((name = list->name) != 0)
- {
- if (strcmp (name, nm.c_str ()) == 0)
- {
- if (usage)
- os << "\nusage: ";
- else
- {
- os << "\n*** " << nm << ":\n\n";
- }
-
- os << list->help << "\n";
-
- return 1;
- }
- list++;
- }
- return 0;
- }
-
- static void
- builtin_help (int argc, const string_vector& argv)
- {
- help_list *op_help_list = operator_help ();
- help_list *kw_help_list = keyword_help ();
-
- for (int i = 1; i < argc; i++)
- {
- if (help_from_list (octave_stdout, op_help_list, argv[i], 0))
- continue;
-
- if (help_from_list (octave_stdout, kw_help_list, argv[i], 0))
- continue;
-
- symbol_record *sym_rec = lookup_by_name (argv[i], 0);
-
- if (sym_rec && sym_rec->is_defined ())
- {
- string h = sym_rec->help ();
-
- if (h.length () > 0)
- {
- print_symbol_type (octave_stdout, sym_rec, argv[i], 1);
- octave_stdout << "\n" << h << "\n";
- continue;
- }
- }
-
- string path = fcn_file_in_path (argv[i]);
-
- string h = get_help_from_file (path);
-
- if (! h.empty ())
- {
- octave_stdout << argv[i] << " is the file:\n"
- << path << "\n\n" << h << "\n";
-
- continue;
- }
-
- octave_stdout << "\nhelp: sorry, `" << argv[i]
- << "' is not documented\n";
- }
-
- additional_help_message (octave_stdout);
- }
-
- #if defined (USE_GNU_INFO)
- DEFUN_TEXT (help, args, ,
- "help [-i] [topic ...]\n\
- \n\
- print cryptic yet witty messages")
- #else
- DEFUN_TEXT (help, args, ,
- "help [topic ...]\n\
- \n\
- print cryptic yet witty messages")
- #endif
- {
- octave_value_list retval;
-
- int argc = args.length () + 1;
-
- string_vector argv = args.make_argv ("help");
-
- if (error_state)
- return retval;
-
- if (argc == 1)
- {
- simple_help ();
- }
- else
- {
- if (argv[1] == "-i")
- {
- help_from_info (argv, 2, argc);
- }
- else
- {
- builtin_help (argc, argv);
- }
- }
-
- return retval;
- }
-
- DEFUN_TEXT (type, args, nargout,
- "type NAME ...]\n\
- \n\
- display the definition of each NAME that refers to a function")
- {
- octave_value_list retval;
-
- begin_unwind_frame ("Ftype");
-
- int argc = args.length () + 1;
-
- string_vector argv = args.make_argv ("type");
-
- if (error_state)
- return retval;
-
- if (argc > 1)
- {
- // XXX FIXME XXX -- we should really use getopt ()
-
- bool quiet = false;
- bool pr_orig_txt = true;
-
- int idx;
-
- for (idx = 1; idx < argc; idx++)
- {
- if (argv[idx] == "-q" || argv[idx] == "-quiet")
- quiet = true;
- else if (argv[idx] == "-t" || argv[idx] == "-transformed")
- pr_orig_txt = false;
- else
- break;
- }
-
- if (idx == argc)
- {
- print_usage ("type");
- return retval;
- }
-
- ostrstream output_buf;
-
- for (int i = idx; i < argc; i++)
- {
- string id = argv[i];
- string elts;
-
- if (id[id.length () - 1] != '.')
- {
- size_t pos = id.find ('.');
-
- if (pos != NPOS)
- {
- elts = id.substr (pos+1);
- id = id.substr (0, pos);
- }
- }
-
- symbol_record *sym_rec = lookup_by_name (id, 0);
-
- if (sym_rec)
- {
- if (sym_rec->is_user_function ())
- {
- tree_fvc *defn = sym_rec->def ();
-
- string fn = defn->fcn_file_name ();
- string ff = fcn_file_in_path (fn);
-
- if (pr_orig_txt && ! ff.empty ())
- {
- ifstream fs (ff.c_str (), ios::in);
-
- if (fs)
- {
- if (nargout == 0 && ! quiet)
- output_buf << argv[i]
- << " is the function defined from:\n"
- << ff << "\n\n";
-
- char ch;
-
- while (fs.get (ch))
- output_buf << ch;
- }
- else
- output_buf << "unable to open `" << ff
- << "' for reading!\n";
- }
- else
- {
- if (nargout == 0 && ! quiet)
- output_buf << argv[i]
- << " is a user-defined function:\n\n";
-
- tree_print_code tpc (output_buf, "", pr_orig_txt);
-
- defn->accept (tpc);
- }
- }
-
- // XXX FIXME XXX -- this code should be shared with
- // Fwhich.
-
- else if (sym_rec->is_text_function ())
- output_buf << argv[i] << " is a builtin text-function\n";
- else if (sym_rec->is_builtin_function ())
- output_buf << argv[i] << " is a builtin function\n";
- else if (sym_rec->is_user_variable ()
- || sym_rec->is_builtin_variable ())
- {
- tree_fvc *defn = sym_rec->def ();
-
- assert (defn && defn->is_constant ());
-
- tree_constant *tmp = (tree_constant *) defn;
-
- int var_ok = 1;
- if (tmp && tmp->is_map ())
- {
- if (! elts.empty ())
- {
- octave_value ult =
- tmp->lookup_map_element (elts, 0, 1);
-
- if (! ult.is_defined ())
- var_ok = 0;
- }
- }
-
- if (nargout == 0 && ! quiet)
- {
- if (var_ok)
- {
- output_buf << argv[i];
- if (sym_rec->is_user_variable ())
- output_buf << " is a user-defined variable\n";
- else
- output_buf << " is a built-in variable\n";
- }
- else
- {
- if (! elts.empty ())
- output_buf << "type: structure `" << id
- << "' has no member `" << elts << "'\n";
- else
- output_buf << "type: `" << id
- << "' has unknown type!\n";
- }
- }
- if (! tmp->is_map ())
- {
- tree_print_code tpc (output_buf, "", pr_orig_txt);
-
- tmp->accept (tpc);
-
- if (nargout == 0)
- output_buf << "\n";
- }
- }
- else
- output_buf << "type: `" << argv[i] << "' has unknown type!\n";
- }
- else
- output_buf << "type: `" << argv[i] << "' undefined\n";
- }
-
- output_buf << ends;
-
- char *s = output_buf.str ();
-
- if (nargout == 0)
- octave_stdout << s;
- else
- retval = s;
-
- delete [] s;
- }
- else
- print_usage ("type");
-
- return retval;
- }
-
- DEFUN_TEXT (which, args, nargout,
- "which NAME ...\n\
- \n\
- display the type of each NAME. If NAME is defined from an function\n\
- file, print the full name of the file.")
- {
- octave_value_list retval;
-
- int argc = args.length () + 1;
-
- string_vector argv = args.make_argv ("which");
-
- if (error_state)
- return retval;
-
- if (argc > 1)
- {
- if (nargout > 0)
- retval.resize (argc-1, Matrix ());
-
- for (int i = 1; i < argc; i++)
- {
- symbol_record *sym_rec = lookup_by_name (argv[i], 0);
-
- if (sym_rec)
- {
- int print = (nargout == 0);
- string tmp = print_symbol_type (octave_stdout, sym_rec,
- argv[i], print);
- if (! print)
- retval(i) = tmp;
- }
- else
- {
- if (nargout == 0)
- octave_stdout << "which: `" << argv[i] << "' is undefined\n";
- else
- retval(i) = "undefined";
- }
- }
- }
- else
- print_usage ("which");
-
- return retval;
- }
-
- static int
- suppress_verbose_help_message (void)
- {
- Vsuppress_verbose_help_message
- = check_preference ("suppress_verbose_help_message");
-
- return 0;
- }
-
- static int
- info_file (void)
- {
- int status = 0;
-
- string s = builtin_string_variable ("INFO_FILE");
-
- if (s.empty ())
- {
- gripe_invalid_value_specified ("INFO_FILE");
- status = -1;
- }
- else
- Vinfo_file = s;
-
- return status;
- }
-
- static int
- info_prog (void)
- {
- int status = 0;
-
- string s = builtin_string_variable ("INFO_PROGRAM");
-
- #ifndef __EMX__
- if (s.empty ())
- {
- gripe_invalid_value_specified ("INFO_PROGRAM");
- status = -1;
- }
- else
- Vinfo_prog = s;
- #else
- Vinfo_prog = s;
- #endif
-
- return status;
- }
-
- void
- symbols_of_help (void)
- {
- DEFVAR (INFO_FILE, Vinfo_file, 0, info_file,
- "name of the Octave info file");
-
- DEFVAR (INFO_PROGRAM, Vinfo_prog, 0, info_prog,
- "name of the Octave info reader");
-
- DEFVAR (suppress_verbose_help_message, 0.0, 0, suppress_verbose_help_message,
- "suppress printing of message pointing to additional help in the\n\
- help and usage functions");
- }
-
- /*
- ;;; Local Variables: ***
- ;;; mode: C++ ***
- ;;; End: ***
- */
-